home *** CD-ROM | disk | FTP | other *** search
/ Internet Info 1994 March / Internet Info CD-ROM (Walnut Creek) (March 1994).iso / networking / ip / ka9q / osrc.arc / ARP.C < prev    next >
Encoding:
C/C++ Source or Header  |  1989-03-26  |  11.0 KB  |  397 lines

  1. /* Address Resolution Protocol (ARP) functions. Sits between IP and
  2.  * Level 2, mapping IP to Level 2 addresses for all outgoing datagrams.
  3.  */
  4. #include "global.h"
  5. #include "mbuf.h"
  6. #include "timer.h"
  7. #include "iface.h"
  8. #include "enet.h"
  9. #include "ax25.h"
  10. #include "icmp.h"
  11. #include "ip.h"
  12. #include "arp.h"
  13.  
  14. static unsigned arp_hash();
  15. static void arp_output();
  16.  
  17. extern int32 Ip_addr;        /* Our IP address */
  18.  
  19. /* ARP entries for particular subnetwork types. The table values
  20.  * are filled in by calls to arp_init() at device attach time
  21.  */
  22. #define    NTYPES    9
  23. struct arp_type Arp_type[NTYPES];
  24.  
  25. /* Hash table headers */
  26. struct arp_tab *Arp_tab[ARPSIZE];
  27.  
  28. struct arp_stat Arp_stat;
  29.  
  30. /* Initialize an entry in the ARP table
  31.  * Called by the device driver at attach time
  32.  */
  33. int
  34. arp_init(hwtype,hwalen,iptype,arptype,pendtime,bdcst,format,scan)
  35. unsigned int hwtype;    /* ARP Hardware type */
  36. int hwalen;        /* Hardware address length */
  37. int iptype;        /* Subnet's protocol ID for IP */
  38. int arptype;        /* Subnet's protocol ID for ARP */
  39. int pendtime;        /* # secs to wait pending response */
  40. char *bdcst;        /* Subnet's broadcast address (if any) */
  41. int (*format)();    /* Function to format hardware addresses */
  42. int (*scan)();        /* Function to scan addresses in ascii */    
  43. {
  44.     register struct arp_type *at;
  45.  
  46.     if(hwtype >= NTYPES)
  47.         return -1;    /* Table too small */
  48.  
  49.     at = &Arp_type[hwtype];
  50.     at->hwalen = (int16)hwalen;
  51.     at->iptype = (int16)iptype;
  52.     at->arptype = (int16)arptype;
  53.     at->pendtime = (int16)pendtime;
  54.     at->bdcst = bdcst;
  55.     at->format = format;
  56.     at->scan = scan;
  57.     return 0;
  58. }
  59.  
  60. /* Resolve an IP address to a hardware address; if not found,
  61.  * initiate query and return NULLCHAR.  If an address is returned, the
  62.  * interface driver may send the packet; if NULLCHAR is returned,
  63.  * res_arp() will have saved the packet on its pending queue,
  64.  * so no further action (like freeing the packet) is necessary.
  65.  */
  66. char *
  67. res_arp(iface,hardware,target,bp)
  68. struct iface *iface;    /* Pointer to interface block */
  69. int16 hardware;        /* Hardware type */
  70. int32 target;        /* Target IP address */
  71. struct mbuf *bp;    /* IP datagram to be queued if unresolved */
  72. {
  73.     register struct arp_tab *arp;
  74.     struct ip ip;
  75.  
  76.     if((arp = arp_lookup(hardware,target)) != NULLARP && arp->state == ARP_VALID)
  77.         return arp->hw_addr;
  78.     if(arp != NULLARP){
  79.         /* Earlier packets are already pending, kick this one back
  80.          * as a source quench
  81.          */
  82.         ntohip(&ip,&bp);
  83.         icmp_output(&ip,bp,QUENCH,0,0);
  84.         free_p(bp);
  85.     } else {
  86.         /* Create an entry and put the datagram on the
  87.          * queue pending an answer
  88.          */
  89.         arp = arp_add(target,hardware,NULLCHAR,0,0);
  90.         enqueue(&arp->pending,bp);
  91.         arp_output(iface,hardware,target);
  92.     }
  93.     return NULLCHAR;
  94. }
  95. /* Handle incoming ARP packets. This is almost a direct implementation of
  96.  * the algorithm on page 5 of RFC 826, except for:
  97.  * 1. Outgoing datagrams to unresolved addresses are kept on a queue
  98.  *    pending a reply to our ARP request.
  99.  * 2. The names of the fields in the ARP packet were made more mnemonic.
  100.  * 3. Requests for IP addresses listed in our table as "published" are
  101.  *    responded to, even if the address is not our own.
  102.  */
  103. void
  104. arp_input(iface,bp)
  105. struct iface *iface;
  106. struct mbuf *bp;
  107. {
  108.     struct arp arp;
  109.     struct arp_tab *ap;
  110.     struct arp_type *at;
  111.     
  112.     Arp_stat.recv++;
  113.     if(ntoharp(&arp,&bp) == -1)    /* Convert into host format */
  114.         return;
  115.     if(arp.hardware >= NTYPES){
  116.         /* Unknown hardware type, ignore */
  117.         Arp_stat.badtype++;
  118.         return;
  119.     }
  120.     at = &Arp_type[arp.hardware];
  121.     if(arp.protocol != at->iptype){
  122.         /* Unsupported protocol type, ignore */
  123.         Arp_stat.badtype++;
  124.         return;
  125.     }
  126.     if(uchar(arp.hwalen) > MAXHWALEN || uchar(arp.pralen) != sizeof(int32)){
  127.         /* Incorrect protocol addr length (different hw addr lengths
  128.          * are OK since AX.25 addresses can be of variable length)
  129.          */
  130.         Arp_stat.badlen++;
  131.         return;
  132.     }
  133.     if(memcmp(arp.shwaddr,at->bdcst,at->hwalen) == 0){
  134.         /* This guy is trying to say he's got the broadcast address! */
  135.         Arp_stat.badaddr++;
  136.         return;
  137.     }
  138.     /* If this guy is already in the table, update its entry
  139.      * unless it's a manual entry (noted by the lack of a timer)
  140.      */
  141.     ap = NULLARP;    /* ap plays the role of merge_flag in the spec */
  142.     if((ap = arp_lookup(arp.hardware,arp.sprotaddr)) != NULLARP
  143.      && ap->timer.start != 0){
  144.         ap = arp_add(arp.sprotaddr,arp.hardware,arp.shwaddr,uchar(arp.hwalen),0);
  145.     }
  146.     /* See if we're the address they're looking for */
  147.     if(arp.tprotaddr == Ip_addr){
  148.         if(ap == NULLARP)    /* Only if not already in the table */
  149.             arp_add(arp.sprotaddr,arp.hardware,arp.shwaddr,uchar(arp.hwalen),0);
  150.  
  151.         if(arp.opcode == ARP_REQUEST){
  152.             /* Swap sender's and target's (us) hardware and protocol
  153.              * fields, and send the packet back as a reply
  154.              */
  155.             memcpy(arp.thwaddr,arp.shwaddr,(int16)uchar(arp.hwalen));
  156.             /* Mark the end of the sender's AX.25 address
  157.              * in case he didn't
  158.              */
  159.             if(arp.hardware == ARP_AX25)
  160.                 arp.thwaddr[uchar(arp.hwalen)-1] |= E;
  161.  
  162.             memcpy(arp.shwaddr,iface->hwaddr,at->hwalen);
  163.             arp.tprotaddr = arp.sprotaddr;
  164.             arp.sprotaddr = Ip_addr;
  165.             arp.opcode = ARP_REPLY;
  166.             if((bp = htonarp(&arp)) == NULLBUF)
  167.                 return;
  168.  
  169.             if(iface->forw != NULLIF)
  170.                 (*iface->forw->output)(iface->forw,
  171.                  arp.thwaddr,iface->forw->hwaddr,at->arptype,bp);
  172.             else 
  173.                 (*iface->output)(iface,arp.thwaddr,
  174.                  iface->hwaddr,at->arptype,bp);
  175.             Arp_stat.inreq++;
  176.         } else {
  177.             Arp_stat.replies++;
  178.         }
  179.     } else if(arp.opcode == ARP_REQUEST
  180.         && (ap = arp_lookup(arp.hardware,arp.tprotaddr)) != NULLARP
  181.         && ap->pub){
  182.         /* Otherwise, respond if the guy he's looking for is
  183.          * published in our table.
  184.          */
  185.         memcpy(arp.thwaddr,arp.shwaddr,(int16)uchar(arp.hwalen));
  186.         /* Mark the end of the sender's AX.25 address
  187.          * in case he didn't
  188.          */
  189.         if(arp.hardware == ARP_AX25)
  190.             arp.thwaddr[uchar(arp.hwalen)-1] |= E;
  191.         memcpy(arp.shwaddr,ap->hw_addr,at->hwalen);
  192.         arp.tprotaddr = arp.sprotaddr;
  193.         arp.sprotaddr = ap->ip_addr;
  194.         arp.opcode = ARP_REPLY;
  195.         if((bp = htonarp(&arp)) == NULLBUF)
  196.             return;
  197.         if(iface->forw != NULLIF)
  198.             (*iface->forw->output)(iface->forw,
  199.              arp.thwaddr,iface->forw->hwaddr,at->arptype,bp);
  200.         else 
  201.             (*iface->output)(iface,arp.thwaddr,
  202.              iface->hwaddr,at->arptype,bp);
  203.         Arp_stat.inreq++;
  204.     }
  205. }
  206. /* Add an IP-addr / hardware-addr pair to the ARP table */
  207. struct arp_tab *
  208. arp_add(ipaddr,hardware,hw_addr,hw_alen,pub)
  209. int32 ipaddr;        /* IP address, host order */
  210. int16 hardware;        /* Hardware type */
  211. char *hw_addr;        /* Hardware address, if known; NULLCHAR otherwise */
  212. int16 hw_alen;        /* Length of hardware address */
  213. int pub;        /* Publish this entry? */
  214. {
  215.     struct mbuf *bp;
  216.     register struct arp_tab *ap;
  217.     unsigned hashval;
  218.  
  219.     if((ap = arp_lookup(hardware,ipaddr)) == NULLARP){
  220.         /* New entry */
  221.         if((ap = (struct arp_tab *)calloc(1,sizeof(struct arp_tab))) == NULLARP)
  222.             return NULLARP;
  223.         ap->timer.func = arp_drop;
  224.         ap->timer.arg = (char *)ap;
  225.         ap->hardware = hardware;
  226.         ap->ip_addr = ipaddr;
  227.  
  228.         /* Put on head of hash chain */
  229.         hashval = arp_hash(hardware,ipaddr);
  230.         ap->prev = NULLARP;
  231.         ap->next = Arp_tab[hashval];
  232.         Arp_tab[hashval] = ap;
  233.         if(ap->next != NULLARP){
  234.             ap->next->prev = ap;
  235.         }
  236.     }
  237.     if(hw_addr == NULLCHAR){
  238.         /* Await response */
  239.         ap->state = ARP_PENDING;
  240.         ap->timer.start = Arp_type[hardware].pendtime * (1000 / MSPTICK);
  241.     } else {
  242.         /* Response has come in, update entry and run through queue */
  243.         ap->state = ARP_VALID;
  244.         ap->timer.start = ARPLIFE * (1000 / MSPTICK);
  245.         free(ap->hw_addr);
  246.         if((ap->hw_addr = malloc(hw_alen)) == NULLCHAR){
  247.             free((char *)ap);
  248.             return NULLARP;
  249.         }
  250.         memcpy(ap->hw_addr,hw_addr,hw_alen);
  251.         /* This kludge marks the end of an AX.25 address to allow
  252.          * for optional digipeaters (insert Joan Rivers salute here)
  253.          */
  254.         if(hardware == ARP_AX25)
  255.             ap->hw_addr[hw_alen-1] |= E;
  256.         ap->pub = pub;
  257.         while((bp = dequeue(&ap->pending)) != NULLBUF)
  258.             ip_route(bp,0);
  259.     }
  260.     start_timer(&ap->timer);
  261.     return ap;
  262. }
  263.  
  264. /* Remove an entry from the ARP table */
  265. void
  266. arp_drop(ap)
  267. register struct arp_tab *ap;
  268. {
  269.     if(ap == NULLARP)
  270.         return;
  271.     stop_timer(&ap->timer);    /* Shouldn't be necessary */
  272.     if(ap->next != NULLARP)
  273.         ap->next->prev = ap->prev;
  274.     if(ap->prev != NULLARP)
  275.         ap->prev->next = ap->next;
  276.     else
  277.         Arp_tab[arp_hash(ap->hardware,ap->ip_addr)] = ap->next;
  278.     free(ap->hw_addr);
  279.     free_q(&ap->pending);
  280.     free((char *)ap);
  281. }
  282.  
  283. /* Look up the given IP address in the ARP table */
  284. struct arp_tab *
  285. arp_lookup(hardware,ipaddr)
  286. int16 hardware;
  287. int32 ipaddr;
  288. {
  289.     register struct arp_tab *ap;
  290.  
  291.     for(ap = Arp_tab[arp_hash(hardware,ipaddr)]; ap != NULLARP; ap = ap->next){
  292.         if(ap->ip_addr == ipaddr && ap->hardware == hardware)
  293.             break;
  294.     }
  295.     return ap;
  296. }
  297. /* Send an ARP request to resolve IP address target_ip */
  298. static void
  299. arp_output(iface,hardware,target)
  300. struct iface *iface;
  301. int16 hardware;
  302. int32 target;
  303. {
  304.     struct arp arp;
  305.     struct mbuf *bp;
  306.     struct arp_type *at;
  307.  
  308.     at = &Arp_type[hardware];
  309.     if(iface->output == NULLFP)
  310.         return;
  311.     
  312.     arp.hardware = hardware;
  313.     arp.protocol = at->iptype;
  314.     arp.hwalen = at->hwalen;
  315.     arp.pralen = sizeof(int32);
  316.     arp.opcode = ARP_REQUEST;
  317.     memcpy(arp.shwaddr,iface->hwaddr,at->hwalen);
  318.     arp.sprotaddr = Ip_addr;
  319.     memset(arp.thwaddr,0,at->hwalen);
  320.     arp.tprotaddr = target;
  321.     if((bp = htonarp(&arp)) == NULLBUF)
  322.         return;
  323.     (*iface->output)(iface,at->bdcst,
  324.         iface->hwaddr,at->arptype,bp);
  325.     Arp_stat.outreq++;
  326. }
  327.  
  328. /* Hash a {hardware type, IP address} pair */
  329. static
  330. unsigned
  331. arp_hash(hardware,ipaddr)
  332. int16 hardware;
  333. int32 ipaddr;
  334. {
  335.     register unsigned hashval;
  336.  
  337.     hashval = hardware;
  338.     hashval ^= hiword(ipaddr);
  339.     hashval ^= loword(ipaddr);
  340.     return hashval % ARPSIZE;
  341. }        
  342. /* Copy a host format arp structure into mbuf for transmission */
  343. struct mbuf *
  344. htonarp(arp)
  345. register struct arp *arp;
  346. {
  347.     struct mbuf *bp;
  348.     register char *buf;
  349.  
  350.     if(arp == (struct arp *)NULL)
  351.         return NULLBUF;
  352.     if((bp = alloc_mbuf(sizeof(struct arp))) == NULLBUF)
  353.         return NULLBUF;
  354.  
  355.     buf = bp->data;
  356.  
  357.     buf = put16(buf,arp->hardware);
  358.     buf = put16(buf,arp->protocol);
  359.     *buf++ = arp->hwalen;
  360.     *buf++ = arp->pralen;
  361.     buf = put16(buf,arp->opcode);
  362.     memcpy(buf,arp->shwaddr,(int16)uchar(arp->hwalen));
  363.     buf += arp->hwalen;
  364.     buf = put32(buf,arp->sprotaddr);
  365.     memcpy(buf,arp->thwaddr,(int16)uchar(arp->hwalen));
  366.     buf += arp->hwalen;
  367.     buf = put32(buf,arp->tprotaddr);
  368.  
  369.     bp->cnt = buf - bp->data;
  370.     return bp;
  371. }
  372. /* Convert an incoming ARP packet into a host-format structure */
  373. int
  374. ntoharp(arp,bpp)
  375. register struct arp *arp;
  376. struct mbuf **bpp;
  377. {
  378.     if(arp == (struct arp *)NULL || bpp == NULLBUFP)
  379.         return -1;
  380.  
  381.     arp->hardware = pull16(bpp);
  382.     arp->protocol = pull16(bpp);
  383.     arp->hwalen = pullchar(bpp);
  384.     arp->pralen = pullchar(bpp);
  385.     arp->opcode = pull16(bpp);
  386.     pullup(bpp,arp->shwaddr,(int16)uchar(arp->hwalen));
  387.     arp->sprotaddr = pull32(bpp);
  388.     pullup(bpp,arp->thwaddr,(int16)uchar(arp->hwalen));
  389.  
  390.     arp->tprotaddr = pull32(bpp);
  391.  
  392.     /* Get rid of anything left over */
  393.     free_p(*bpp);
  394.     *bpp = NULLBUF;
  395.     return 0;
  396. }
  397.